package com.alex.formates.umd;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.util.Vector;

import android.util.Log;

import com.alex.books.BaseBook;
import com.alex.books.Chapter;
import com.alex.formates.ReaderPlugin;

public class UMDPlugin extends ReaderPlugin {

	private int mBufBegin;
	private int mBufEnd;
	private String mText;
	private int chapterNumber;

	
	@Override
	public Object decode(BaseBook book, File file) {
		// TODO Auto-generated method stub
		prase(book,file);
		book.mReaderingInfo.mCurChapter = book.mChapters.get(book.mReaderingInfo.mIndex); 
		mBaseBook = book;
		mBufBegin = mBufEnd  = (int) book.mReaderingInfo.mMarkPos;
		return null;

	}

	@Override
	public Object generatedCatalog(BaseBook book, File file, int mode) {
		// TODO Auto-generated method stub
		prase(book,file);
		mBaseBook = book;
		return null;
	}
	

	@Override
	public boolean isFirstChapter() {
		// TODO Auto-generated method stub
		if(mBaseBook.mReaderingInfo.mIndex <= 0){
			return true;
		}
		return false;
	}


	@Override
	public boolean isLastChapter() {
		// TODO Auto-generated method stub
		if(mBaseBook.mReaderingInfo.mIndex >= mBaseBook.mChapters.size()-1){
			return true;
		}
		return false;
	}

	@Override
	public boolean isFirstPage() {
		// TODO Auto-generated method stub
		if(mBaseBook.mReaderingInfo.mIndex <= 0
				&&	mBufBegin <= mBaseBook.mChapters.get(0).mPosBegin){
				return true;
			}
		return false;
	}
	
	@Override
	public boolean isLastPage() {
		// TODO Auto-generated method stub
		if(mBaseBook.mReaderingInfo.mIndex >= mBaseBook.mChapters.size()-1
			&&	mBufEnd >= mBaseBook.mReaderingInfo.mCurChapter.mPosEnd){
			return true;
		}
		return false;
	}

	@Override
	public String nextChapter() {
		if(mBaseBook.mReaderingInfo.mIndex+1<mBaseBook.mChapters.size()){
			mBaseBook.mReaderingInfo.mIndex++;
			mBaseBook.mReaderingInfo.mCurChapter = mBaseBook.mChapters.get(mBaseBook.mReaderingInfo.mIndex);
			mBaseBook.mReaderingInfo.mMarkPos = mBaseBook.mReaderingInfo.mCurChapter.mPosBegin;
		}
		mBufEnd = (int)mBaseBook.mReaderingInfo.mMarkPos;
		StringBuffer text = new StringBuffer();
		mLines.clear();
		mLines = getPageNextText(mBaseBook.mReaderingInfo.mCurChapter.mPosEnd);
		for(int i=0;i<mLines.size();i++){
			text.append(mLines.get(i)+"\n");
		}
		Log.d("nextPage", "text:"+text);
		return text.toString();
	}

	@Override
	public String nextPage() {
		// TODO Auto-generated method stub
		
		if(mBufEnd >= mBaseBook.mReaderingInfo.mCurChapter.mPosEnd && 
				mBaseBook.mReaderingInfo.mIndex+1<mBaseBook.mChapters.size()){
			mBaseBook.mReaderingInfo.mIndex++;
			mBaseBook.mReaderingInfo.mCurChapter = mBaseBook.mChapters.get(mBaseBook.mReaderingInfo.mIndex);
			mBaseBook.mReaderingInfo.mMarkPos = mBaseBook.mReaderingInfo.mCurChapter.mPosBegin;
			mBufEnd = (int)mBaseBook.mReaderingInfo.mCurChapter.mPosBegin;
		}
		StringBuffer text = new StringBuffer();
		mLines.clear();
		mLines = getPageNextText(mBaseBook.mReaderingInfo.mCurChapter.mPosEnd);
		for(int i=0;i<mLines.size();i++){
			text.append(mLines.get(i)+"\n");
			Log.d("nextPage"+i, "text:"+mLines.get(i));
		}
		
		return text.toString();
	}

	@Override
	public String previousChapter() {
		// TODO Auto-generated method stub
		if(mBaseBook.mReaderingInfo.mIndex-1>=0){
			mBaseBook.mReaderingInfo.mIndex--;
			mBaseBook.mReaderingInfo.mCurChapter = mBaseBook.mChapters.get(mBaseBook.mReaderingInfo.mIndex);
			mBaseBook.mReaderingInfo.mMarkPos = mBaseBook.mReaderingInfo.mCurChapter.mPosBegin;
		}
		mBufEnd = (int)mBaseBook.mReaderingInfo.mMarkPos;
		StringBuffer text = new StringBuffer();
		mLines.clear();
		mLines = getPageNextText(mBaseBook.mReaderingInfo.mCurChapter.mPosEnd);
		for(int i=0;i<mLines.size();i++){
			text.append(mLines.get(i)+"\n");
		}
		Log.d("nextPage", "text:"+text);
		return text.toString();
	}

	@Override
	public String previousPage() {
		if(mBufBegin <= mBaseBook.mReaderingInfo.mCurChapter.mPosBegin 
				&& mBaseBook.mReaderingInfo.mIndex-1>=0){
				mBaseBook.mReaderingInfo.mIndex--;
				mBaseBook.mReaderingInfo.mCurChapter = mBaseBook.mChapters.get(mBaseBook.mReaderingInfo.mIndex);
				mBaseBook.mReaderingInfo.mMarkPos = mBaseBook.mReaderingInfo.mCurChapter.mPosEnd;
				mBufBegin = (int)mBaseBook.mReaderingInfo.mMarkPos;
			}
			
			StringBuffer text = new StringBuffer();
			mLines.clear();
			mLines = getPagePrevious();
			for(int i=0;i<mLines.size();i++){
				text.append(mLines.get(i)+"\n");
				Log.d("previousPage "+i,mLines.get(i));
			}
			return text.toString();
	}

	@Override
	public String refreshPage() {
		mBaseBook.mReaderingInfo.mCurChapter = mBaseBook.mChapters.get(mBaseBook.mReaderingInfo.mIndex);
		mBufEnd = (int) mBaseBook.mReaderingInfo.mMarkPos;
		StringBuffer text = new StringBuffer();
		mLines.clear();
		mLines = getPageNextText(mBaseBook.mReaderingInfo.mCurChapter.mPosEnd);
		for(int i=0;i<mLines.size();i++){
			text.append(mLines.get(i)+"\n");
			Log.d("nextPage"+i, "text:"+mLines.get(i));
		}
		
		return text.toString();
	}
	
	
	/**
	 * 获取下一页数据
	 * @param endPos
	 * @return
	 */
	private Vector<String> getPageNextText(long endPos){
		mBaseBook.mReaderingInfo.mMarkPos = mBufEnd;
		mBufBegin = mBufEnd;
		String strParagraph = "";
		while(mLines.size() <= 0){
			while(mLines.size() < mReaderFormate.mLineCount && mBufEnd < endPos){
				strParagraph = readParagraphNext(mBufEnd);
				String strReturn = "";

				if (strParagraph.length() == 0) {
					mLines.add(strParagraph);
				}
				mBufEnd = mBufEnd + strParagraph.length()+strReturn.length();
				while (strParagraph.length() > 0) {
					int nSize = mReaderFormate.mPaint.breakText(strParagraph, true, mReaderFormate.mPageW,
							null);
					mLines.add(strParagraph.substring(0, nSize));
					strParagraph = strParagraph.substring(nSize);
					if (mLines.size() >= mReaderFormate.mLineCount) {
						break;
					}
				}
				
				if (strParagraph.length() != 0) {
						mBufEnd -= (strParagraph+ strReturn)
								.length();
				}
			}
		}
		return mLines;
	}
	
	private String readParagraphNext(int nFromPos){
		String text = mBaseBook.mReaderingInfo.mCurChapter.mContent.substring(nFromPos+1);
		int end = text.length();
		if(text.indexOf("\r")!= -1){
			end = text.indexOf("\r");
		}else if(text.indexOf("\n\n")!= -1){
			end = text.indexOf("\n\n");
		}else if(text.indexOf("\n")!= -1){
			end = text.indexOf("\n");
		}else if(text.indexOf("\r\n")!= -1){
			end = text.indexOf("\r\n");
		}
		
		return mBaseBook.mReaderingInfo.mCurChapter.mContent.substring(nFromPos, nFromPos+1+end);
	}

	private Vector<String> getPagePrevious(){
		if(mBufBegin <= mBaseBook.mChapters.get(0).mPosBegin)
			mBufBegin = (int)mBaseBook.mChapters.get(0).mPosBegin;
		mBufEnd = mBufBegin;
		String strParagraph = "";
		while(mLines.size() <=0){
			while(mLines.size() < mReaderFormate.mLineCount && mBufBegin>=0){
				Vector<String> paraLines = new Vector<String>();
				strParagraph= readParagraphPrevious(mBufBegin);
				mBufBegin -= strParagraph.length();
				
				strParagraph = strParagraph.replaceAll("\r\n", "");
				strParagraph = strParagraph.replaceAll("\n", "");
				if (strParagraph.length() == 0) {
					paraLines.add(strParagraph);
				}
				while (strParagraph.length() > 0) {
					int nSize = mReaderFormate.mPaint.breakText(strParagraph, true, mReaderFormate.mPageW,
							null);
					paraLines.add(strParagraph.substring(0, nSize));
					strParagraph = strParagraph.substring(nSize);
				}
				mLines.addAll(0, paraLines);
			}
			while (mLines.size() > mReaderFormate.mLineCount) {
					mBufBegin += mLines.get(0).length();
					mLines.remove(0);
			}
		}
		mBaseBook.mReaderingInfo.mMarkPos = mBufBegin;
		return mLines;
	}
	
	/**
	 * 读取上一段落
	 * @param nFromPos
	 * @return
	 */
	private String readParagraphPrevious(int nFromPos){
		String text = mBaseBook.mReaderingInfo.mCurChapter.mContent.substring(0,nFromPos);
		int end = 0;
		if(text.lastIndexOf("\r")!= -1){
			end = text.lastIndexOf("\r");
		}else if(text.lastIndexOf("\n\n")!= -1){
			end = text.lastIndexOf("\n\n");
		}else if(text.lastIndexOf("\n")!= -1){
			end = text.lastIndexOf("\n");
		}else if(text.lastIndexOf("\r\n")!= -1){
			end = text.lastIndexOf("\r\n");
		}
		
		return mBaseBook.mReaderingInfo.mCurChapter.mContent.substring(end, nFromPos);
	}
	
	int end0;
	private void prase(BaseBook book, File file){
		book.mChapters = new Vector<Chapter>();
		UMDInputStream in = null;
		int random1;
		int random2;
		int size = 0;
		StringBuffer buffer;
		StringBuffer bufferContent = new StringBuffer();
		byte b;
		int type;
		try {
			in = new UMDInputStream(new FileInputStream(file));

			int header = in.readInt();
			if (header != -560292983) {
				in.close();
				throw new Exception("It's not a umd file!");
			}
			boolean flag = true;
			b = in.readByte();
			while (flag) {
				switch (b) {
				case '#':
					type = in.readUnsignedShort();
					switch (type) {

					case 1:
						in.skipBytes(2);
						int umd_type = in.readUnsignedByte();
						if (umd_type != 1) {
							in.close();
							throw new Exception("It's not a text umd file!");
						}
						in.skipBytes(2);
						break;
					case 2:
						buffer = new StringBuffer();
						in.skipBytes(1);
						size = in.readUnsignedByte();
						for (int i = 0; i < (size - 5) / 2; i++) {
							char c = in.readChar();
							buffer.append(c);
						}
						Log.d("", "title" + buffer.toString());
						break;
					case 3:
						buffer = new StringBuffer();
						in.skipBytes(1);
						size = in.readUnsignedByte();
						for (int i = 0; i < (size - 5) / 2; i++) {
							char c = in.readChar();
							buffer.append(c);
						}
						Log.d("", "title" + buffer.toString());
						break;
					case 4:
						buffer = new StringBuffer();
						in.skipBytes(1);
						size = in.readUnsignedByte();
						for (int i = 0; i < (size - 5) / 2; i++) {
							char c = in.readChar();
							buffer.append(c);
						}
						Log.d("", "title" + buffer.toString());
						break;
					case 5:
						buffer = new StringBuffer();
						in.skipBytes(1);
						size = in.readUnsignedByte();
						for (int i = 0; i < (size - 5) / 2; i++) {
							char c = in.readChar();
							buffer.append(c);
						}
						Log.d("", "title" + buffer.toString());
						break;
					case 6:
						buffer = new StringBuffer();
						in.skipBytes(1);
						size = in.readUnsignedByte();
						for (int i = 0; i < (size - 5) / 2; i++) {
							char c = in.readChar();
							buffer.append(c);
						}
						Log.d("", "title" + buffer.toString());
						break;
					case 7:
						buffer = new StringBuffer();
						in.skipBytes(1);
						size = in.readUnsignedByte();
						for (int i = 0; i < (size - 5) / 2; i++) {
							char c = in.readChar();
							buffer.append(c);
						}
						Log.d("", "title" + buffer.toString());
						break;
					case 8:
						buffer = new StringBuffer();
						in.skipBytes(1);
						size = in.readUnsignedByte();
						for (int i = 0; i < (size - 5) / 2; i++) {
							char c = in.readChar();
							buffer.append(c);
						}
						Log.d("", "title" + buffer.toString());
						break;
					case 9:
						buffer = new StringBuffer();
						in.skipBytes(1);
						size = in.readUnsignedByte();
						for (int i = 0; i < (size - 5) / 2; i++) {
							char c = in.readChar();
							buffer.append(c);
						}
						Log.d("", "title" + buffer.toString());
						break;
					case 0x0b:
						in.skipBytes(2);
						end0 = in.readInt() / 2;
						break;
					case 0x83:
						in.skipBytes(2);
						random1 = in.readInt();
						in.skipBytes(1);
						random2 = in.readInt();
						if (random1 != random2) {
							in.close();
							throw new Exception("It's not a umd file!");
						}
						chapterNumber = (in.readInt() - 9) / 4;
						Log.d("", "chapterNumber" + chapterNumber);
						int offsets[] = new int[chapterNumber];
						for (int i = 0; i < offsets.length; i++) {
							offsets[i] = in.readInt() / 2;
							
						}

						int beg=offsets[0];
						int end=0;
						for(int i=0;i<offsets.length-1;i++){
							end = offsets[i+1];
							Chapter chapter = new Chapter();
							chapter.mChapterIndex = i;
							chapter.mBookId = book.mBookId;
							chapter.mPosBegin = 0;
							chapter.mPosEnd = end - beg;
							chapter.mLength = end - beg;
							Log.d("", "offsets:" +chapter.mPosEnd);
							book.mChapters.add(chapter);
							beg = end;
						}
						Chapter chapter = new Chapter();
						chapter.mChapterIndex = offsets.length-1;
						chapter.mBookId = book.mBookId;
						chapter.mPosBegin = 0;
						chapter.mPosEnd = end0 - beg;
						chapter.mLength = end0 - beg;
						book.mChapters.add(chapter);
						
						break;
					case 0x84:
						in.skipBytes(2);
						random1 = in.readInt();
						in.skipBytes(1);
						random2 = in.readInt();
						if (random1 != random2) {
							in.close();
							throw new Exception("It's not a umd file!");
						}

						in.readInt();
						for (int i = 0; i < chapterNumber; i++) {
							int titleLength = in.readUnsignedByte() / 2;
							StringBuffer titleBuf = new StringBuffer();
							for (int j = 0; j < titleLength; j++) {
								char c = in.readChar();
								titleBuf.append(c);
							}
							
							book.mChapters.get(i).mChapterName = titleBuf.toString();
							Log.d("", "chapter.mChapterName:"+titleBuf.toString());
							
						}

						break;
					case 0x81:
						in.skipBytes(2);
						random1 = in.readInt();
						in.skipBytes(1);
						random2 = in.readInt();
						if (random1 != random2) {
							in.close();
							throw new Exception("It's not a umd file!");
						}
						int dataBlockNum = (in.readInt() - 9) / 4;
						in.skipBytes(dataBlockNum * 4);
						break;
					case 0x82:

						in.skipBytes(3);
						random1 = in.readInt();
						in.skipBytes(1);
						random2 = in.readInt();
						if (random1 != random2) {
							in.close();
							throw new Exception("It's not a umd file!");
						}

						int coverLength = in.readInt() - 9;
						byte covers[] = new byte[coverLength];
						in.read(covers);
						break;
					case 0x87:
						in.skipBytes(4);
						random1 = in.readInt();
						in.skipBytes(1);
						random2 = in.readInt();
						if (random1 != random2) {
							in.close();
							throw new Exception("It's not a umd file!");
						}
						int offsetLentgth = in.readInt() - 9;
						in.skipBytes(offsetLentgth);
						break;
					case 0x0a:
						in.skipBytes(2);
						in.readInt();
						break;
					case 0x0c:
						in.skipBytes(2);
						int fileSize = in.readInt();
						flag = false;
						continue;
					case 0xf1:
						in.skipBytes(2);
						in.skipBytes(16);
						break;
					default:
						flag = false;
						break;

					}
					Log.d("", "type:" + type);
					break;
				case 0x24:

					random1 = in.readInt();
					int dataLength = in.readInt() - 9;
					byte bytes[] = new byte[dataLength];
					in.read(bytes);

					ByteArrayOutputStream bos = new ByteArrayOutputStream();
					InflaterOutputStream zos = new InflaterOutputStream(bos);
					zos.write(bytes);
					zos.close();
					//String chapterContents[] = new String[umd.chapterNumber];

					UMDInputStream tmp = new UMDInputStream(
							new ByteArrayInputStream(bos.toByteArray()));

					bufferContent.append(tmp.toUnicodeString());
					
					tmp.close();

					break;
				default:
					flag = false;
					break;
				}

				b = in.readByte();
			}

		} catch (EOFException eof) {
			eof.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			mText  = bufferContent.toString();
			int i =0;
			int number = 0;
			book.mWordNumber = ""+mText.length();
			for(i =0;i<book.mChapters.size();i++){
				book.mChapters.get(i).mContent = mText.substring((int)(book.mChapters.get(i).mPosBegin), (int)(book.mChapters.get(i).mPosEnd));
				mText = mText.substring((int)book.mChapters.get(i).mPosEnd);
			}
		}
	}

}
